﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using NPMonitor.DataModel;
using NPMonitor.Implementation.Internal;
using NPMonitor.Interfaces;
using System.Data.Objects;
using System.Data.SqlClient;
using NPMonitor.Helpers;
using System.Collections.Generic;
using NPMonitor.Utility;

namespace NPMonitor.Implementation.Store
{
    public class MachineStore : IMachineStore
    {
        #region Machine Function
        /// <summary>
        /// 获取所有机器
        /// </summary>
        /// <returns></returns>
        public ReadOnlyCollection<MachineData> GetAllMachines()
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.OrderByDescending(p => p.RegistDate).ToList().AsReadOnly();
            }
        }

        /// <summary>
        /// 分页获取所有机器
        /// </summary>
        /// <returns></returns>
        public ReadOnlyCollection<MachineData> GetAllMachines(int pageIndex, int pageSizes)
        {
            if (pageIndex < 0)
            {
                pageIndex = 0;
            }
            if (pageSizes < 0)
            {
                pageSizes = int.MaxValue;
            }
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.OrderByDescending(p => p.LastHeartbeat).Skip(pageIndex * pageSizes).Take(pageSizes).ToList().AsReadOnly();
            }
        }

        /// <summary>
        /// 获取所有机器的总数
        /// </summary>
        /// <returns></returns>
        public int GetAllMachinesTotalCount()
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.Count();
            }
        }

        /// <summary>
        /// 根据机器pool id 获取所有机器
        /// </summary>
        /// <param name="poolId"></param>
        /// <returns></returns>
        public ReadOnlyCollection<MachineData> GetMachinesByPoolId(int poolId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.Where(p => p.PoolId == poolId).ToList().AsReadOnly();
            }
        }

        /// <summary>
        /// 根据机器pool id 分页获取所有机器
        /// </summary>
        /// <param name="poolId"></param>
        /// <returns></returns>
        public ReadOnlyCollection<MachineData> GetMachinesByPoolId(int poolId, int pageIndex, int pageSizes)
        {
            if (pageIndex < 0)
            {
                pageIndex = 0;
            }
            if (pageSizes < 0)
            {
                pageSizes = int.MaxValue;
            }
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.Where(p => p.PoolId == poolId).OrderByDescending(p => p.LastHeartbeat).Skip(pageIndex * pageSizes).Take(pageSizes).ToList().AsReadOnly();
            }
        }

        /// <summary>
        /// 根据机器pool id 获取所有机器的总数
        /// </summary>
        /// <param name="poolId"></param>
        /// <returns></returns>
        public int GetAllMachinesTotalCountByPoolId(int poolId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.Where(p => p.PoolId == poolId).Count();
            }
        }

        /// <summary>
        /// Get All MachinePool From Database
        /// </summary>
        /// <returns></returns>
        public ReadOnlyCollection<MachinePool> GetAllMachinePool()
        {
            using (DbStoreContext dbsc = new DbStoreContext())
            {
                return dbsc.MachinePool.ToList().AsReadOnly();
            }
        }

        /// <summary>
        /// Query the MachineInfo from Database By MachineID
        /// </summary>
        /// <param name="machineId"></param>
        /// <returns></returns>
        public MachineData GetMachineInfoById(int machineId)
        {
            using (DbStoreContext dbsc = new DbStoreContext())
            {
                return dbsc.Machines.FirstOrDefault(p => p.MachineId == machineId);
            }
        }


        /// <summary>
        /// Update The MachineInfo By MachineId
        /// </summary>
        /// <param name="mdInfo"></param>
        /// <returns></returns>
        public void EditMachine(MachineData mdInfo)
        {
            using (DbStoreContext dbsc = new DbStoreContext())
            {
                MachineData machine = dbsc.Machines.FirstOrDefault(d => d.MachineId == mdInfo.MachineId);
                machine.Description = mdInfo.Description;
                machine.PoolId = mdInfo.PoolId;
                dbsc.SaveChanges();
            }
        }

        /// <summary>
        /// find machine info by machine name
        /// </summary>
        /// <param name="machineName"></param>
        /// <returns></returns>
        public MachineData GetMachineByMachineName(string machineName)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Machines.FirstOrDefault(x => x.MachineName == machineName);
            }
        }

        /// <summary>
        /// Heart beat
        /// </summary>
        /// <param name="machineName"></param>
        /// <returns>
        /// -1: Can't found machine, need to register machine first
        /// 1: beated successfully
        /// </returns>
        public bool Heartbeat(string machineName)
        {
            try
            {
                SqlHelper.ExecuteNonQuery(
                    "Update Machines Set LastHeartbeat = GetUTCDate() WHERE MachineName = @machineName",
                    new SqlParameter[] { new SqlParameter("machineName", machineName) }, 
                    5); // timeout if exceeded 5 seconds

                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool CheckAndRegisterMachine(MachineInfo machineInfo)
        {
            MachineData md = GetMachineByMachineName(machineInfo.MachineName);

            if (md == null)
            {
                md = new MachineData(machineInfo);
                md.RegistDate = Helpers.Utils.CurrentServerUtcTime;
                md.LastHeartbeat = md.RegistDate;

                using (var ctx = new DbStoreContext())
                {
                    ctx.Entry(md).State = System.Data.EntityState.Added;

                    ctx.Machines.Add(md);

                    ctx.SaveChanges();

                    return true;
                }
            }

            return false;
        }
        #endregion

        #region MachinePool Function

        /// <summary>
        /// 获取MachinePool数量
        /// </summary>
        /// <returns></returns>
        public int GetMachinePoolCount()
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.MachinePool.Count();
            }
        }

        /// <summary>
        /// 根据机器池Id获取池信息
        /// </summary>
        /// <param name="poolId"></param>
        /// <returns></returns>
        public MachinePool GetMachinePoolInfoById(int poolId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.MachinePool.FirstOrDefault(p => p.PoolId == poolId);
            }
        }

        /// <summary>
        /// 获取分页MachinePool信息
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSizes"></param>
        /// <returns></returns>
        public List<MachinePool> GetAllMachinePool(int pageIndex, int pageSizes)
        {
            if (pageIndex < 0)
            {
                pageIndex = 0;
            }
            if (pageSizes < 0)
            {
                pageSizes = int.MaxValue;
            }
            using (DbStoreContext dbsc = new DbStoreContext())
            {
                var pool = from p in dbsc.MachinePool
                           select p;
                return pool.OrderByDescending(d => d.PoolId).Skip(pageIndex * pageSizes).Take(pageSizes).ToList();
            }
        }

        /// <summary>
        /// 保存MachinePool信息
        /// </summary>
        /// <param name="PoolId"></param>
        /// <param name="machinePool"></param>
        public void SavePoolInfo(int PoolId, MachinePool machinePool)
        {
            using (var ctx = new DbStoreContext())
            {
                if (PoolId == 0)
                {
                    ctx.MachinePool.Add(machinePool);
                }
                else
                {
                    var specificPool = ctx.MachinePool.FirstOrDefault(d => d.PoolId == PoolId);
                    if (specificPool != null)
                    {
                        specificPool.PoolName = machinePool.PoolName;
                        specificPool.Comments = machinePool.Comments;
                    }
                }
                ctx.SaveChanges();
            }
        }

        public bool DeletePoolById(int PoolId)
        {
            using (var ctx = new DbStoreContext())
            {
                var pool = ctx.Machines.FirstOrDefault(d => d.PoolId == PoolId);
                var specificPool = ctx.MachinePool.FirstOrDefault(d => d.PoolId == PoolId);
                if (specificPool != null && pool == null)
                {
                    ctx.MachinePool.Remove(specificPool);
                    ctx.SaveChanges();
                    return true;
                }
                else
                    return false;
            }
        }

        public bool CheckPool(int poolId, string PoolName)
        {
            using (var ctx = new DbStoreContext())
            {
                var pool = ctx.MachinePool.FirstOrDefault(d => d.PoolName == PoolName && d.PoolId != poolId);
                if (pool != null)
                {
                    return true;
                }
                else
                    return false;
            }
        }

        public bool CheckPoolMachine(int poolId)
        {
            using (var ctx = new DbStoreContext())
            {
                var pool = ctx.Machines.FirstOrDefault(d => d.PoolId == poolId);
                if (pool != null)
                {
                    return true;
                }
                else
                    return false;
            }
        }
        #endregion
    }
}
